//////////////////////////////////////////////////////////////////////////////
//	Filename:			WinMain.cpp
//
//	Date Created:		8/26/2011
//	File Creator:		Steven Broyles
//
//	Last Modified:		8/26/2011	
//	Modifier Initials:	SB
//
//	Description:		To provide a basic window framework for Windows projects.
//////////////////////////////////////////////////////////////////////////////
#include <Windows.h>

// Debugging tools
#include <DbgHelp.h>
#include "Utils/CDebugConsole.h"

#if _DEBUG
//#define VLD_OPT_AGGREGATE_DUPLICATES	// don't show me the same leak 5000 times
#define VLD_MAX_DATA_DUMP 0

#include <vld.h>

// Detect memory leaks
#define _CRTDBG_MAP_ALLOC
#include <cstdlib>
#include <crtdbg.h>
#endif

// Globals and #defines
#define SCREEN_WIDTH	1280
#define SCREEN_HEIGHT	960

bool g_bPause				 = false;				// Whether or not to stop processing OUR code
const char* g_szWinClassName = "Cthulhu";			// Window Class Name.
const char* g_szWinTitle	 = "Project Cthulhu";	// Window Title.

const int	g_nWinWidth		 = SCREEN_WIDTH;		// Window Width. 
const int	g_nWinHeight	 = SCREEN_HEIGHT;		// Window Height.

#if _DEBUG
	const BOOL	g_bIsWindowed			= TRUE;		// If in Debug, show the main window border
#else
	const BOOL	g_bIsWindowed			= FALSE;	// If in Release, do not show the main window border
#endif

// Used to create a dumpfile is there is a crash outside of a debugger
LONG WINAPI Hanndler( _EXCEPTION_POINTERS * exPointers )
{
	HANDLE theFile = CreateFileA( "myDumpFile.mdmp", GENERIC_WRITE, FILE_SHARE_WRITE, 
		NULL, CREATE_ALWAYS, FILE_ATTRIBUTE_NORMAL, NULL );

	if( theFile != INVALID_HANDLE_VALUE )
	{
		_MINIDUMP_EXCEPTION_INFORMATION exInfo;

		exInfo.ThreadId = GetCurrentThreadId(  );
		exInfo.ClientPointers = NULL;
		exInfo.ExceptionPointers = exPointers;

		MiniDumpWriteDump( GetCurrentProcess(  ), GetCurrentProcessId(  ),
			theFile, MiniDumpNormal, &exInfo, NULL, NULL );

		MessageBoxA( NULL, "myDumpFile.mdmp", "MiniDump was created", MB_OK );
	}

	return EXCEPTION_EXECUTE_HANDLER;
}

LRESULT CALLBACK WindowProc(HWND hWnd, UINT msg, WPARAM wParam, LPARAM lParam)
{
	//	This is the main message handler of the system.

	//	What is the message 
	switch(msg)
	{
		//	To skip ALT pop up menu (system menu)
	case WM_SYSKEYUP:
	case WM_SYSCHAR:
		return(0);
		break;

		//	Handle ALT+F4
	case WM_CLOSE:
		{
			// Sends us a WM_DESTROY
			DestroyWindow(hWnd);			
		}
		break;

		//	and lose/gain focus
	case WM_ACTIVATE:
		{
			//	gaining focus
			if (LOWORD(wParam) != WA_INACTIVE)
			{
				//Unpause
				g_bPause = true;
			}
			else // losing focus
			{
				// Pause
				g_bPause = false;
			}
		}
		break;

	case WM_CREATE: 
		{
			//	Do initialization here

			return(0);
		}
		break;

	case WM_PAINT:
		{
			return(0);
		}
		break;

	case WM_DESTROY: 
		{
			//	Kill the application
			PostQuitMessage(0);
			return(0);
		}
		break;

	default:
		break;
	}

	//	Process any messages that we didn't take care of 
	return (DefWindowProc(hWnd, msg, wParam, lParam));
}

///////////////////////////////////////////////////////////////////////////////////////
//	This makes sure we do not run duplicates of our game! This should be called
// immediately upon entering the MAIN loop. 
///////////////////////////////////////////////////////////////////////////////////////
BOOL CheckIfAlreadyRunning(void)
{
	//	Find a window of the same window class name and window title
	HWND hWnd = FindWindow(g_szWinClassName, g_szWinTitle);

	///////////////////////////////////////////////////////////////////////////////////////
	//Fun little tidbit on how to run only 1 copy of a program on windows
	///////////////////////////////////////////////////////////////////////////////////////

	//	If one was found
	if (hWnd)
	{
		//	If it was minimized
		if (IsIconic(hWnd))
			//	restore it
			ShowWindow(hWnd, SW_RESTORE);

		//	Bring it to the front
		SetForegroundWindow(hWnd);

		return TRUE;
	}

	//	No other copies found running
	return FALSE;
}


BOOL RegisterWindowClass(HINSTANCE hInstance)
{
	WNDCLASSEX	winClassEx;	//	This will describe the window class we will create.

	//	First fill in the window class structure
	winClassEx.cbSize			= sizeof(winClassEx);
	winClassEx.style			= CS_DBLCLKS | CS_OWNDC | CS_HREDRAW | CS_VREDRAW;
	winClassEx.lpfnWndProc		= WindowProc;
	winClassEx.cbClsExtra		= 0;
	winClassEx.cbWndExtra		= 0;
	winClassEx.hInstance		= hInstance;
	winClassEx.hIcon			= NULL; //LoadIcon(NULL, MAKEINTRESOURCE(IDI_ICON1));
	winClassEx.hIconSm			= NULL;
	winClassEx.hCursor			= LoadCursor(NULL, IDC_ARROW);
	winClassEx.hbrBackground	= NULL; //(HBRUSH)GetStockObject(BLACK_BRUSH);
	winClassEx.lpszMenuName		= NULL; 
	winClassEx.lpszClassName	= g_szWinClassName;
	winClassEx.hIconSm = NULL;

	//	Register the window class
	return RegisterClassEx(&winClassEx);
}

//	Creates and sizes the window appropriately depending on if 
//	the application is windowed or full screen.
HWND MakeWindow(HINSTANCE hInstance)
{
	// Setup window style flags
	DWORD dwWindowStyleFlags = WS_VISIBLE;

	if (g_bIsWindowed)
	{
		dwWindowStyleFlags |= WS_OVERLAPPEDWINDOW;
	}
	else
	{
		dwWindowStyleFlags |= WS_POPUP;
		ShowCursor(FALSE);	// Stop showing the mouse cursor
	}

	// Setup the desired client area size
	RECT rWindow;
	rWindow.left	= 0;
	rWindow.top		= 0;
	rWindow.right	= g_nWinWidth;
	rWindow.bottom	= g_nWinHeight;

	// Get the dimensions of a window that will have a client rect that
	// will really be the resolution we're looking for.
	AdjustWindowRectEx(&rWindow, 
		dwWindowStyleFlags,
		FALSE, 
		WS_EX_APPWINDOW);

	// Calculate the width/height of that window's dimensions
	int nWindowWidth	= rWindow.right - rWindow.left;
	int nWindowHeight	= rWindow.bottom - rWindow.top;

	//	Create the window
	return CreateWindowEx(WS_EX_APPWINDOW,											//	Extended Style flags.
		g_szWinClassName,									//	Window Class Name.
		g_szWinTitle,											//	Title of the Window.
		dwWindowStyleFlags,										//	Window Style Flags.
		(GetSystemMetrics(SM_CXSCREEN)/2) - (nWindowWidth/2),		//	Window Start Point (x, y). 
		(GetSystemMetrics(SM_CYSCREEN)/2) - (nWindowHeight/2),	//		-Does the math to center the window over the desktop.
		nWindowWidth,												//	Width of Window.
		nWindowHeight,											//	Height of Window.
		NULL,														//	Handle to parent window.
		NULL,														//	Handle to menu.
		hInstance,												//	Application Instance.
		NULL);													//	Creation parameters.
}

//////////////////////////
//		WinMain			//
//////////////////////////
int WINAPI WinMain(HINSTANCE hInstance, HINSTANCE hPrevInstance, LPSTR lpCmdLine, int nCmdShow)
{
	MSG		msg;	//	Generic message.
	HWND	hWnd;	//	Main Window Handle.
	//CGame* m_pGM = NULL;

	//See Comments on "CheckIfAlreadyRunning"
	if (!hPrevInstance)
	{
		if (CheckIfAlreadyRunning())
			return FALSE;
	}

	//	Register the window class
	if (!RegisterWindowClass(hInstance))
		return 0;

	//	Create the window
	hWnd = MakeWindow(hInstance);

	if (!hWnd)
		return 0;

	ShowWindow(hWnd, nCmdShow);
	UpdateWindow(hWnd);

	// set up our dump file function
	SetUnhandledExceptionFilter( Hanndler );

	//SetupDebugConsole(  );

	SetForegroundWindow( hWnd );

	// set up cgame
	//m_pGM = CGame::GetInstance();
	//m_pGM->Initialize(hWnd, hInstance, g_nWinWidth, g_nWinHeight, false);
	//////////////////////////////////////////

	RECT *windRect = new RECT;
	GetWindowRect( hWnd, windRect );

	//m_pGM->SetWindowPosX( (float)windRect->left );
	//m_pGM->SetWindowPosY( (float)windRect->top );

	delete windRect;

	//	Enter main event loop
	while (TRUE)
	{
		if (PeekMessage(&msg, NULL, 0, 0, PM_REMOVE))
		{ 
			//	Test if this is a quit
			if (msg.message == WM_QUIT)
				break;

			//	Translate any accelerator keys
			TranslateMessage(&msg);

			//	Send the message to the window proc
			DispatchMessage(&msg);
		}

		//////////////////////////////////
		//	Game Loop
		//////////////////////////////////
		//if(!m_pGM->Main())
		//	PostQuitMessage(0);
		//////////////////////////////////
	}

	/////////////////////////////////////////
	//	Cleanup
	/////////////////////////////////////////
	//m_pGM->Shutdown();
	/////////////////////////////////////////


	//	Unregister the window class
	UnregisterClass(g_szWinClassName, hInstance);


	//	Return to Windows like this.
	return (int)(msg.wParam);
}